#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
#include <assert.h>
#include "personnage.h"

void initPerso (personnage* perso)
{
	assert (perso != NULL);
	perso->sante = 0;
	perso->nbVies = 0;
	perso->score = 0;
	perso->nbMunitions = 0;
	perso->munition = NULL;
	perso->hitBox = NULL;
	perso->posCP = 0;
}

void setPersonnage (personnage* perso, int sante, int vies, int score, const float posX, const float posY, projectile* arme, const int nbMunitions, bloc* persoBloc)
{
	int i;
	assert (perso != NULL);
	assert (perso->munition == NULL);
	assert (perso->hitBox == NULL);
	assert (sante > 0);
	assert (vies > 0);
	assert (posX >= 0 && posY >= 0);
	assert (nbMunitions > 0);
	perso->hitBox = malloc (sizeof (bloc));
	perso->nbMunitions = nbMunitions;
	perso->munition = malloc (nbMunitions*sizeof (projectile*));
	for (i = 0 ; i < nbMunitions ; i++)
	{
		perso->munition[i] = malloc (sizeof(projectile));
		initProjectile (perso->munition[i]);
		copieProjectile (arme, perso->munition[i]);
	}
	perso->sante = sante;
	perso->nbVies = vies;
	perso->score = score;
	copieBloc (persoBloc, perso->hitBox);
	setPosition (perso->hitBox, posX, posY);
	perso->posCP = posX/32;
}

void copiePersonnage (personnage* P1, personnage* P2)
{
	assert (P1 != NULL);
	setPersonnage (P2, P1->sante, P1->nbVies, P1->score, P1->hitBox->pos.x, P1->hitBox->pos.y, P1->munition[0], P1->nbMunitions, P1->hitBox);
}
/*
void accroupir (personnage *perso)
{

}
*/

void personnageToucheEnnemi (personnage *perso, personnage* Ennemi)
{
	assert (perso != NULL);
	assert (Ennemi != NULL);
	perso->sante -= Ennemi->munition[0]->degats;
}

void personnageToucheProjectile (personnage *perso, projectile* armeEnnemi)
{
	assert (perso != NULL);
	assert (armeEnnemi != NULL);
	perso->sante -= armeEnnemi->degats;
}

void resurrectionPerso (terrain* T, personnage* Perso)
{
    setPosition(Perso->hitBox, T->tab[T->CP[Perso->posCP]][0]->pos.x, T->tab[0][0]->dim);
}

void mortPersonnage (terrain* T, personnage *perso)
{
	assert (perso != NULL);
	perso->nbVies--;
    if (perso->nbVies > 0)
    {
        resurrectionPerso (T, perso);
    }
}

void setSanteMonte (personnage *perso, int bonus)
{
	assert (perso != NULL);
	assert (bonus > 0);
	perso->sante += bonus;
}

void setViePlus (personnage *perso)
{
	assert (perso != NULL);
	perso->nbVies++;
}

void setScore (personnage *perso, int score)
{
	assert (perso != NULL);
	assert (score > 0);
	perso->score += score;
}

int getScore (personnage* perso)
{
	assert (perso != NULL);
	return perso->score;
}

void initCelluleEnnemi (celluleEnnemi* C)
{
	assert (C != NULL);
	C->Ennemi = NULL;
	C->Suivant = NULL;
	C->action = 0;
}

void initListeEnnemis (listeEnnemis* L)
{
	assert (L != NULL);
	L->Boss = NULL;
	L->nbEnnemis = 0;
}

void ajouteEnnemi (listeEnnemis* L, personnage* typeEnnemi, const int x, const int y, const int action)
{
	assert (L != NULL);
	assert (typeEnnemi != NULL);
	celluleEnnemi* Repere;
	celluleEnnemi* nouvelEnnemi = malloc (sizeof(celluleEnnemi));
	initCelluleEnnemi (nouvelEnnemi);
	nouvelEnnemi->Ennemi = malloc (sizeof (personnage));
	initPerso (nouvelEnnemi->Ennemi);
	copiePersonnage (typeEnnemi, nouvelEnnemi->Ennemi);
	setPosition (nouvelEnnemi->Ennemi->hitBox, x, y);
	nouvelEnnemi->action = action;
	if (L->Boss == NULL)
	{
		L->Boss = nouvelEnnemi;
	}
	else
	{
		Repere = L->Boss;
		while (Repere->Suivant != NULL)
		{
			Repere = Repere->Suivant;
		}
		nouvelEnnemi->Suivant = Repere->Suivant;
		Repere->Suivant = nouvelEnnemi;
	}
	L->nbEnnemis++;
}

void infligeDegatsSurEnnemi (listeEnnemis* L, personnage* P, int position)
{
	int i;
	celluleEnnemi* Repere;
	assert (L != NULL);
	assert (P != NULL);
	assert (position > 0);
	assert (position <= L->nbEnnemis);
	Repere = L->Boss;
	for (i = 1 ; i<position ; i++)
	{
		Repere = Repere->Suivant;
	}
	Repere->Ennemi->sante -= P->munition[0]->degats;
	if (Repere->Ennemi->sante <= 0)
	{
		setScore (P, Repere->Ennemi->score);
		supprimeEnnemi (L, position);
	}
}

void videPerso (personnage* P)
{
	int i;
	assert (P != NULL);
	supprimeBloc (P->hitBox);
	for (i = 0 ; i < P->nbMunitions ; i++)
	{
		videProjectile (P->munition[i]);
		free (P->munition[i]);
	}
	free (P->munition);
	initPerso (P);
}

void supprimeEnnemi (listeEnnemis* L, int position)
{
	int i;
	assert (L != NULL);
	assert (position > 0 && position <= L->nbEnnemis);
	celluleEnnemi* Repere;
	celluleEnnemi* Precedent;
	Precedent = L->Boss;
	if (position == 1)
    {
        videListeEnnemis (L);
    }
    else
    {
        for (i = 2 ; i<position ; i++)
        {
            Precedent = Precedent->Suivant;
        }
        Repere = Precedent->Suivant;
        Precedent->Suivant = Repere->Suivant;
        videPerso (Repere->Ennemi);
        free (Repere->Ennemi);
        free (Repere);
		L->nbEnnemis--;
    }
}

void videListeEnnemis (listeEnnemis* L)
{
	assert (L != NULL);
	assert (L->Boss != NULL);
	while (L->Boss->Suivant != NULL)
	{
		supprimeEnnemi (L, 1);
	}
	videPerso (L->Boss->Ennemi);
	free (L->Boss->Ennemi);
	free (L->Boss);
	initListeEnnemis (L);
}

void verifCheckPoint (terrain* T, personnage* Heros)
{
	if (Heros->hitBox->pos.x > T->CP[Heros->posCP+1])
	{
		Heros->posCP++;
	}
}

void personnageTestRegression()
{
	personnage Perso, Mechant, Boss;
	listeEnnemis ListeE;
	bloc hitBox, armePerso, hitBoss, hitBossProjectile;
	projectile Arme, ArmeMechant, armeBoss;
	terrain Niveau;

    initTerrain(&Niveau);
    setTerrain(&Niveau, "terrain.txt", 32);
	initPerso (&Perso);

	if (Perso.sante != 0 || Perso.nbVies != 0 || Perso.score != 0 || Perso.munition != NULL || Perso.hitBox != NULL)
	{
		printf("Problème avec initPerso...\n\n");
	}
	else
	{
		printf("initPerso est OK ! \n\n");
	}

	initPerso (&Mechant);
	initPerso (&Boss);

	initBloc (&hitBox);
	initBloc (&armePerso);
	initBloc (&hitBoss);
	initBloc (&hitBossProjectile);

	initProjectile (&Arme);
	initProjectile (&ArmeMechant);
	initProjectile (&armeBoss);

	setBloc (&hitBox, 10, 1, 'P');
	setBloc (&hitBoss, 30, 1, 'B');
	setBloc (&hitBossProjectile, 5, 1, '*');
	setBloc (&armePerso, 1, 1, '.');

	setPosition (&hitBox, 0, 0);

	setProjectile (&Arme, 30, 10, &armePerso);
	setProjectile (&ArmeMechant, 20, 10, &armePerso);
	setProjectile (&armeBoss, 80, 15, &hitBossProjectile);

	setPersonnage (&Perso, 300, 3, 0, 160, 800, &Arme, 4, &hitBox);
	/* Verification de setPersonnage */
	if (Perso.sante != 300)
	{
		printf("Problème avec la sante de setPersonnage...\n\n");
	}
	else if (Perso.nbVies != 3)
	{
		printf("Problème avec les vies de setPersonnage...\n\n");
	}
	else if (Perso.score != 0)
	{
		printf("Problème avec les vies de setPersonnage...\n\n");
	}
	else if (Perso.hitBox->pos.x != 160 || Perso.hitBox->pos.y != 800)
	{
		printf("Problème avec la position de setPersonnage...\n\n");
	}
	else
	{
		printf ("setPersonnage est OK ! \n\n");
	}

	setPersonnage (&Mechant, 200, 1, 500, 300, 500, &ArmeMechant, 3, &hitBox);
	setPersonnage (&Boss, 300, 1, 2000, 10, 10, &armeBoss, 5, &hitBoss);

	setPosition (Mechant.hitBox, 165, 800);

	mortPersonnage (&Niveau, &Perso);

	/* Verification de mortPersonnage */
	if (Perso.nbVies != 2)
	{
		printf("Problème avec mortPersonnage...\n\n");
	}
	else
	{
		printf("mortPersonnage est OK !\n\n");
	}

	setViePlus (&Perso);

	/* Verification de setViePlus */
	if (Perso.nbVies != 3)
	{
		printf("Problème avec setViePlus...\n\n");
	}
	else
	{
		printf("setViePlus est OK !\n\n");
	}

	setScore (&Perso, 500);

	/* Verification de setScore */
	if (Perso.score != 500)
	{
		printf("Probleme avec setScore...\n\n");
	}
	else
	{
		printf("setScore est OK ! \n\n");
	}

	/* Verification de getScore */
	if (getScore (&Perso) != 500)
	{
		printf("Probleme avec getScore...\n\n");
	}
	else
	{
		printf("getScore est OK !\n\n");
	}

	initListeEnnemis (&ListeE);

	/* Verification de initListeEnnemis */
	if (ListeE.Boss != NULL || ListeE.nbEnnemis != 0)
	{
		printf("Probleme avec initListeEnnemis...\n\n");
	}
	else
	{
		printf("initListeEnnemis est OK !\n\n");
	}

	ajouteEnnemi (&ListeE, &Boss, 6000, 1800, 1);

	/* Verification de ajouteEnnemi */
	if (ListeE.Boss == NULL)
	{
		printf("Probleme d'allocation memoire dans ajouteEnnemi...\n\n");
	}
	else if (ListeE.Boss->Ennemi->hitBox->pos.x != 6000 || ListeE.Boss->Ennemi->hitBox->pos.y != 1800)
	{
		printf("Probleme de position dans ajouteEnnemi...\n\n");
	}
	else if (ListeE.nbEnnemis != 1)
	{
		printf("Probleme de decompte des personnages dans ajouteEnnemi...\n\n");
	}
	else
	{
		printf("On peut au moins ajouter un Boss avec ajouteEnnemi !\n\n");
	}

	ajouteEnnemi (&ListeE, &Mechant, 330, 270, 3);

	if (ListeE.Boss->Suivant == NULL)
	{
		printf("Probleme de chainage de liste avec ajouteEnnemi...\n\n");
	}
	else if (ListeE.nbEnnemis != 2)
	{
		printf("Probleme de decompte des personnages dans ajouteEnnemi...\n\n");
	}
	else
	{
		printf("ajouteEnnemi est definitivement OK !\n\n");
	}

	ajouteEnnemi (&ListeE, &Mechant, 640, 972, 5);


	videListeEnnemis (&ListeE);
	videPerso (&Perso);
	videPerso (&Mechant);
	videPerso (&Boss);
	videProjectile (&Arme);
	videProjectile (&ArmeMechant);
	videProjectile (&armeBoss);
/*

void supprimeEnnemi (listeEnnemis* L, int position);*/

}

